/////////////////////////////////////////////////////////////////////////////////////////////
// Filename: D3DClass.cpp
// 
//	THIS SUBSYSTEM IS ONLY TO BE USED BY THE APPLICATIONLAYER CLASS !
//
// (c) Dave Ottley, 2012. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////
#ifndef D3DCLASS_H
#define D3DCLASS_H

///////////////////////////
//		INCLUDES
///////////////////////////
#include <D3D11.h>
#include <xnamath.h>
#include <vector>

///////////////////////////
//		MY INCLUDES
///////////////////////////
#include "StateMachine.h"
#include "Constants.h"

class Rect;

///////////////////////////
//		D3DCLASS
///////////////////////////
class D3DClass
{
	ID3D11Device * mDevice;
	ID3D11DeviceContext * mContext;
	IDXGISwapChain * mSwapChain;
	ID3D11RenderTargetView * mRenderTargetView;
	ID3D11DepthStencilView * mDepthStencilView;
	ID3D11Texture2D * mDepthStencilBuffer;
	ID3D11Texture2D * mBackBuffer;
	ID3D11DepthStencilState * mDepthEnabledStencilState;
	ID3D11DepthStencilState * mDepthDisabledStencilState;
	ID3D11RasterizerState * mRasterizerState;
	ID3D11VertexShader * mVertexShader;
	ID3D11PixelShader * mPixelShader;
	ID3D11SamplerState * mSamplerLinear;
	ID3D11InputLayout * mVertexLayout;
	ID3DBlob * mVSBlob;
	ID3DBlob * mPSBlob;
	ID3D11Debug * mDebug;
	D3D11_VIEWPORT mViewport;
	D3D_FEATURE_LEVEL mFeatureLevel;
	D3D_DRIVER_TYPE mDriverType;
	XMFLOAT4X4 mIWorld;
	XMFLOAT4X4 mOrtho;
	XMFLOAT4X4 mProj;
	XMFLOAT4X4 mView;
	XMFLOAT4 mCameraPos;
	XMFLOAT4 mCameraTarget;
	unsigned int mVRam;
	unsigned int mRefreshNumerator;
	unsigned int mRefreshDenominator;
	unsigned int mID;
	uint32_t mIndexedAtlasedSpriteCounter;
	bool mVSync;
	bool mFullscreen;
	float mNearPlane;
	float mFarPlane;
	char mVideoCardDescription[256];
	wchar_t mDriverTypeName[100];
	wchar_t mFeatureLevelName[100];
	StateMachine<D3DClass> * mStateMachine;
	ID3D11Buffer * mStockIndexBuffer;

	struct NonAtlasedSpriteResourceBundle
	{
		ID3D11ShaderResourceView * texture;
		ID3D11Buffer *	vertexBuffer;	
	};

	struct SimpleVertex
	{
		XMFLOAT3 Pos;
		XMFLOAT2 Tex;
	};

	ID3D11ShaderResourceView * mCurrentMasterAtlas;
	uint32_t mAtlasWidth, mAtlasHeight;
	std::vector<NonAtlasedSpriteResourceBundle> mNonAtlasedSpriteResources;
	std::vector<SimpleVertex> mAtlasedVertexBuffer;
	std::vector<uint32_t> mAtlasedIndexBuffer;
	

public:
	//SINGLETON
	static D3DClass * GetInstance();
private:
	D3DClass();
	~D3DClass();
	D3DClass(const D3DClass&);
	D3DClass& operator=(const D3DClass& rhs);
public:
	//PUBLIC INTERFACE
	void OnResize();
	bool Initialize();
	void Shutdown();
	void ClearScreen();
	void Draw(Rect sourceRect, Rect destRect, void * texture);
	void DrawAtlased(Rect sourceRect, Rect destRect);
	void SetAtlas(std::wstring filename);
	void Present();
	void TurnZBufferOn();
	void TurnZBufferOff();
	void ToggleFullscreen() { mFullscreen = !mFullscreen; mSwapChain->SetFullscreenState(mFullscreen, NULL); OnResize(); }
	void ToggleDebugConsole() {}
	bool CreateTextureFromFile(std::wstring filename, void * const * texture);
	void ReleaseResource( void ** resource );
	StateMachine<D3DClass> * GetFSM() const { return mStateMachine; }
	bool HandleMessage(const Telegram& msg) { return mStateMachine->HandleMessage(msg); }
	const bool IsDeviceActive() const { if(mDevice) return true; else return false; }
	const float GetAspectRatio() const;
	const bool GetFullscreen() const { return mFullscreen; }
	void GetVideoCardInfo(char* cardName, int& memory) const;
	void GetProjectionMatrix(XMMATRIX& projectionMatrix);
	void GetIWorldMatrix(XMMATRIX& worldMatrix);
	void GetOrthoMatrix(XMMATRIX& orthoMatrix);

	//Setters
	void SetFullscreen(bool fullscreen) { mFullscreen = fullscreen; }

private:
	bool QueryVideoCardInfo();
	bool CreateDeviceAndSwapChain();
	bool CreateRenderTargetView();
	bool CreateDepthStencilView();
	bool SetViewport(PlayerCount players);
	bool SetRasterizerState();
	bool MakeWindowAssociation();
	bool LoadCompiledShadersFromFile();
	bool LoadShaderFromFile(const wchar_t * filename, ID3DBlob ** blob);
	bool CreateSamplerState();
	bool CreateLayout(const void * vertexBuffer, int size);
	void SetPrimitiveTopology();
	bool UpdateQuadVertexBuffer(void * vertexBuffer, const Rect &sourceRect, const Rect &destRect);
	HRESULT CreateQuadVertexBuffer(ID3D11Buffer ** buffer);
	HRESULT CreateVertexBuffer(ID3D11Buffer ** buffer, const std::vector<SimpleVertex> &vertices);
	HRESULT CreateQuadIndexBuffer(ID3D11Buffer ** buffer);
	HRESULT CreateIndexBuffer(ID3D11Buffer ** buffer, const std::vector<uint32_t> &indices);
	void SetBuffers(ID3D11Buffer ** indexBuffer, ID3D11Buffer ** vertexBuffer);
	
};

#ifndef D3DCls
#define D3DCls D3DClass::GetInstance()
#endif

#endif // D3DCLASS_H